package demo.shiro;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import demo.Result;
import demo.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Shiro 自定义 Filter
 *
 * @author 肖溥博文
 * @version 1.1
 */
@Component
public class JwtFilter extends AuthenticatingFilter {

    @Autowired
    JwtUtil jwtUtil;

    // 创建 token
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String jwt = request.getHeader("Authorization");
        if (StrUtil.isEmpty(jwt)) {
            return null;
        }

        return new JwtToken(jwt);
    }

    // 当访问不被允许时
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String jwt = request.getHeader("Authorization");
        if (StrUtil.isEmpty(jwt)) {
            return true;
        }
        // 校验 Jwt
        Claims claims = jwtUtil.getClaimByToken(jwt);
        if (claims == null || jwtUtil.isTokenExpired(claims.getExpiration())) {
            throw new ExpiredCredentialsException("Token 失效，请重新登陆");
        }
        // 执行登录
        return executeLogin(servletRequest, servletResponse);
    }

    // 当登陆失败时
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        Throwable throwable = e.getCause() == null ? e : e.getCause();
        Result result = Result.error(throwable.getMessage());
        String json = JSONUtil.toJsonStr(result);

        try {
            httpServletResponse.getWriter().println(json);
        } catch (IOException ioException) {
            e.printStackTrace();
        }

        return false;
    }
}
